// This is the interface to the JVM that we'll
// call the majority of our methods on.
use jni::JNIEnv;

// These objects are what you should use as arguments to your native function.
// They carry extra lifetime information to prevent them escaping from the
// current local frame (which is the scope within which local (temporary)
// references to Java objects remain valid)
use jni::objects::{GlobalRef, JClass, JObject, JString};

use jni::objects::JByteArray;
use jni::objects::JIntArray;
use jni::sys::{jint, jlong};

use photon_rs::PhotonImage;

use photon_rs::filters;


#[no_mangle]
pub extern "system" fn Java_ai_moqi_fingerprint_common_ImageProcLib_clahe___3IIIII<'local>(
    // Notice that this `env` argument is mutable. Any `JNIEnv` API that may
    // allocate new object references will take a mutable reference to the
    // environment.
    mut env: JNIEnv<'local>,
    // this is the class that owns our static method. Not going to be used, but
    // still needs to have an argument slot
    _class: JClass<'local>,
    int_array: JIntArray<'local>,
    width: jint,
    height: jint,
    block_number: jint,
    limit: jint,
) -> JByteArray<'local> {
    // 传入的是java int[]，但是值一定都在0～255之间，先获取长度
    let len = env.get_array_length(&int_array).unwrap();

    // 定义出 rust Vec<u8> 的集合，长度同输入
    let mut byte_buffer: Vec<i32> = vec![0; len as usize];
    let slice: &mut [i32] = &mut byte_buffer;

    // 将输入的值赋值到 rust Vec<u8> 集合中
    env.get_int_array_region(&int_array, 0, slice).unwrap();

    // let mut vec_u8: Vec<u8> = byte_buffer.into_iter().map(|x| x as u8).collect();
    let mut vec_u8: Vec<u8> = Vec::new();
    let mut a = 0;
    for i in 0..len {
        let index = i as usize;
        vec_u8.push(byte_buffer[index] as u8);
    }
    a = vec_u8[0];
    let mut photon_image = PhotonImage::new(vec_u8, width as u32, height as u32);

    // default block_number is 8, limit is 48
    filters::clahe(&mut photon_image, block_number as u32, limit as u32);
    let buf = photon_image.get_raw_pixels();

    let output = env.byte_array_from_slice(&buf).unwrap();
    output
}

#[no_mangle]
pub extern "system" fn Java_ai_moqi_fingerprint_common_ImageProcLib_clahe___3BIIII<'local>(
    // Notice that this `env` argument is mutable. Any `JNIEnv` API that may
    // allocate new object references will take a mutable reference to the
    // environment.
    mut env: JNIEnv<'local>,
    // this is the class that owns our static method. Not going to be used, but
    // still needs to have an argument slot
    _class: JClass<'local>,
    byte_array: JByteArray<'local>,
    width: jint,
    height: jint,
    block_number: jint,
    limit: jint,
) -> JByteArray<'local> {
    let mut vec_u8: Vec<u8> = env.convert_byte_array(&byte_array).unwrap();

    let mut photon_image = PhotonImage::new(vec_u8, width as u32, height as u32);

    // default block_number is 8, limit is 48
    filters::clahe(&mut photon_image, block_number as u32, limit as u32);
    let buf = photon_image.get_raw_pixels();

    let output = env.byte_array_from_slice(&buf).unwrap();
    output
}


#[no_mangle]
pub extern "system" fn Java_ai_moqi_fingerprint_common_ImageProcLib_testByteArrTrans<'local>(
    // Notice that this `env` argument is mutable. Any `JNIEnv` API that may
    // allocate new object references will take a mutable reference to the
    // environment.
    mut env: JNIEnv<'local>,
    // this is the class that owns our static method. Not going to be used, but
    // still needs to have an argument slot
    _class: JClass<'local>,
    byte_array: JByteArray<'local>,
) -> JString<'local> {
    // First, we have to get the byte[] out of java.
    let _input = env.convert_byte_array(&byte_array).unwrap();

    let a = _input[0];
    let b = _input[1];

    let my_string = env
        .new_string(format!("Image Proc from Rust! {} -- {}", a, b))
        .expect("Couldn't create java string!");
    my_string
}
